package tinybase.rm;
import java.nio.ByteBuffer;

import tinybase.basic.BytePointer;
import tinybase.basic.RC;
import tinybase.pf.*;

public class RM_Manager {
	public static final int RM_PAGE_LIST_END    =-1;
	public static final int RM_HEADER_PAGE_NUM = 0;	
	//je choisi 5 arbitraire,en fait je sais pas il dois etre combien
	public static final int RM_FILE_HDR_SIZE= (int)5;
	
    private	PF_Manager pPfm;

	public RM_Manager() {
		pPfm=new PF_Manager();
	}
	
	RC createFile(String fileName, int recordSize) {
	     PF_FileHandle pfFileHandle=new PF_FileHandle();
		 PF_PageHandle pageHandle=new PF_PageHandle();
		 BytePointer refArray = new BytePointer();
		 PageNum refPageNum = new PageNum();
		 RM_FileHdr rmFileHdr=new RM_FileHdr();
		

	 
		 if (recordSize >= tinybase.pf.Pf.PF_PAGE_SIZE -RM_FILE_HDR_SIZE || recordSize < 1)
		    return (RC.RM_INVALIDRECSIZE);
		RC rc;
		if((rc=pPfm.createFile(fileName))!=RC.RM_SUCCESS)
			return (rc);
		if((rc=pPfm.openFile(fileName, pfFileHandle))!=RC.RM_SUCCESS)
			return(rc);
		if((rc=pfFileHandle.allocatePage(pageHandle))!=RC.RM_SUCCESS)
			return(rc);
		if(((rc=pageHandle.getData(refArray))!=RC.RM_SUCCESS)||(rc=pageHandle.getPageNum(refPageNum))!=RC.RM_SUCCESS)
			return(rc);
		ByteBuffer.wrap(refArray.getArray()).putInt(0, refPageNum.getPageNum());
		
		rmFileHdr.setFirstFree(RM_PAGE_LIST_END);		
		rmFileHdr.setRecordSize(recordSize); 
		
	
		rmFileHdr.setNumRecordsPerPage((int)((tinybase.pf.Pf.PF_PAGE_SIZE - RM_FILE_HDR_SIZE - 1) 
                / (recordSize + 1.0/8))); 
		
		
		   if (recordSize * (rmFileHdr.getNumRecordsPerPage() + 1) 
		       + rmFileHdr.getNumRecordsPerPage() / 8 
		       <=tinybase.pf.Pf.PF_PAGE_SIZE -RM_FILE_HDR_SIZE - 1)
			   
			   rmFileHdr.setNumRecordsPerPage(rmFileHdr.getNumRecordsPerPage()+1);
		   
		
		      rmFileHdr.setPageHeaderSize(RM_FILE_HDR_SIZE 
		                             + (rmFileHdr.getNumRecordsPerPage() + 7) / 8);
		      
		      rmFileHdr.setNumRecords(0);
		      
		      // Mark the header page as dirty
		      if ((rc =pfFileHandle.markDirty(RM_HEADER_PAGE_NUM))!=RC.PF_SUCCESS)
		           return rc;
		      
		      // Unpin the header page
		      if ((rc = pfFileHandle.unpinPage(RM_HEADER_PAGE_NUM))!=RC.PF_SUCCESS)
		    	  return rc;
		      
		      // Call PF_Manager::CloseFile()
		      if ((rc = pPfm.closeFile(pfFileHandle))!=RC.PF_SUCCESS)
		    	  return rc;
		      
		return RC.RM_SUCCESS;
	}
	
	RC destroyFile(String fileName) {
		RC rc;
		if((rc=pPfm.destroyFile(fileName))!=RC.RM_SUCCESS)
			return (rc);
		return RC.RM_SUCCESS;
	}
	
	RC openFile(String fileName, RM_FileHandle rmFileHandle) {
		   RC rc;
		   PF_PageHandle pfPageHandle=new PF_PageHandle();
		   BytePointer pData=new BytePointer();
		   
		   // Call PF_Manager::OpenFile()
		   if ((rc = pPfm.openFile(fileName, rmFileHandle.pfFileHandle))!=RC.PF_SUCCESS)
		      // Test: non-existing fileName, opened fileHandle
		      return rc;

		   // Get the header page
		   if ((rc = rmFileHandle.pfFileHandle.getFirstPage(pfPageHandle))!=RC.PF_SUCCESS)
		      // Test: invalid file
		      return rc;

		   // Get a pointer where header information resides
		   if ((rc = pfPageHandle.getData(pData))!=RC.PF_SUCCESS)
		      // Should not happen
			   return rc;

		   // Read the file header (from the buffer pool to RM_FileHandle)
		   ByteBuffer.wrap(pData.getArray());
		   // Unpin the header page
		   if ((rc = rmFileHandle.pfFileHandle.unpinPage(RM_HEADER_PAGE_NUM))!=RC.PF_SUCCESS)
		      // Should not happen
		      return rc;
		   // TODO: cannot guarantee the validity of file header at this time

		   // Set file header to be not changed
		   rmFileHandle.setBHdrChanged(true);
		
		return RC.RM_SUCCESS;
	}
		
	RC closeFile(RM_FileHandle rmFileHandle) {
		   RC rc;
		   
		   // Write back the file header if any changes made to the header 
		   // while the file is open
		   if (rmFileHandle.bHdrChanged==true) {
		      PF_PageHandle pfPageHandle=new PF_PageHandle();
		      BytePointer refArray=new BytePointer();
		      PageNum refPageNum=new PageNum();

		      // Get the header page
		      if ((rc = rmFileHandle.pfFileHandle.getFirstPage(pfPageHandle))!=RC.PF_SUCCESS)
		         // Test: unopened(closed) fileHandle, invalid file
		        return rc;
		  	      
		      // Write the file header (to the buffer pool)
		      if(((rc=pfPageHandle.getData(refArray))!=RC.RM_SUCCESS)||(rc=pfPageHandle.getPageNum(refPageNum))!=RC.RM_SUCCESS)
					return(rc);
				ByteBuffer.wrap(refArray.getArray()).putInt(0, refPageNum.getPageNum());
				

		      // Mark the header page as dirty
		      if ((rc = rmFileHandle.pfFileHandle.markDirty(RM_HEADER_PAGE_NUM))!=RC.PF_SUCCESS)
		         // Should not happen
		    	  return rc;
		      
		      // Unpin the header page
		      if ((rc = rmFileHandle.pfFileHandle.unpinPage(RM_HEADER_PAGE_NUM))!=RC.PF_SUCCESS)
		         // Should not happen
		    		  return rc;

		      // Set file header to be not changed
		      rmFileHandle.setBHdrChanged(true);
		   }

		   // Call PF_Manager::CloseFile()
		   if ((rc = pPfm.closeFile(rmFileHandle.pfFileHandle))!=RC.PF_SUCCESS)
		      // Test: unopened(closed) fileHandle
		     return rc;

		   // Reset member variables
		   rmFileHandle.fileHdr.setFirstFree(RM_PAGE_LIST_END);

		return RC.RM_SUCCESS;
	}
	
	
}
